package com.soup.lab.vavr;

import io.vavr.*;
import io.vavr.collection.Stream;
import io.vavr.control.Either;
import io.vavr.control.Option;
import io.vavr.control.Try;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.concurrent.atomic.AtomicInteger;

public class VavrBaseTestCase {

    @Test
    public void test() {
        Try.of(() -> 1 / 0)
                .onSuccess(System.out::println)
                .onFailure(Throwable::printStackTrace)
                .recover(ArithmeticException.class, 0)
                .andFinally(() -> System.out.println("finally"))
                .andThen(System.out::print);
    }

    @Test
    public void testCurrying() {
        Function4<Integer, Integer, Integer, Integer, Integer> sum4 = (a, b, c, d) -> a + b + c + d;
        Function1<Integer, Function1<Integer, Function1<Integer, Integer>>> carried = sum4.curried().apply(2);
        Integer apply = carried.apply(3).apply(4).apply(5);
        System.out.println(apply);

    }

    @Test
    public void testEither() {
        Assertions.assertEquals(calculate("a", 1).getLeft(), "-1");
        Assertions.assertEquals(calculate(1, 3).get(), 4);
    }

    private Either<String, Integer> calculate(Object a, Object b) {
        if (a instanceof Number && b instanceof Number) {
            return Either.right(((Number) a).intValue() + ((Number) b).intValue());
        }
        return Either.left("-1");
    }

    @Test
    public void testLazy() {
        AtomicInteger i = new AtomicInteger(1);
        Lazy<Integer> lazyVal = Lazy.of(i::get);
        i.addAndGet(2);
        Assertions.assertFalse(lazyVal.isEvaluated());
        Assertions.assertEquals(3, lazyVal.get());
        i.addAndGet(2);
        Assertions.assertEquals(3, lazyVal.get());
    }

    @Test
    public void testTuple() {
        Tuple2<Integer, String> before = Tuple.of(1, "abc");
        Tuple2<Integer, String> after = before.map(a -> a + 1, b -> b + 1);
        Assertions.assertEquals(before._1, 1);
        Assertions.assertEquals(before._2, "abc");
        Assertions.assertEquals(after._1, 2);
        Assertions.assertEquals(after._2, "abc1");
    }

    @Test
    public void testOption() {
        Lazy<Boolean> lazy = Lazy.of(() -> Option.of("abc").map(a -> null).map(o -> o.equals(1)).getOrElse(false));
        Assertions.assertThrows(NullPointerException.class, lazy::get);
        Assertions.assertEquals(Option.of("abc").getClass(), Option.Some.class);
        Assertions.assertEquals(Option.of(null).getClass(), Option.None.class);
    }

}
